home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Text / Edit / ElVIs / src / opts.c < prev    next >
C/C++ Source or Header  |  1992-04-07  |  17KB  |  798 lines

  1. /* opts.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the code that manages the run-time options -- The 
  12.  * values that can be modified via the "set" command.
  13.  */
  14.  
  15. #include "config.h"
  16. #include "vi.h"
  17. #include "ctype.h"
  18. #ifndef NULL
  19. #define NULL (char *)0
  20. #endif
  21. extern char    *getenv();
  22.  
  23. /* maximum width to permit for strings, including ="" */
  24. #define MAXWIDTH 20
  25.  
  26. /* These are the default values of all options */
  27. char    o_autoindent[1] =    {FALSE};
  28. char    o_autoprint[1] =    {TRUE};
  29. char    o_autotab[1] =        {TRUE};
  30. char    o_autowrite[1] =     {FALSE};
  31. char    o_columns[3] =        {80, 32, 255};
  32. char    o_directory[30] =    TMPDIR;
  33. char    o_edcompatible[1] =    {FALSE};
  34. char    o_equalprg[80] =    {"fmt"};
  35. char    o_errorbells[1] =    {TRUE};
  36. char    o_exrefresh[1] =    {TRUE};
  37. char    o_ignorecase[1] =    {FALSE};
  38. char    o_keytime[3] =        {2, 0, 50};
  39. char    o_keywordprg[80] =    {KEYWORDPRG};
  40. char    o_lines[3] =        {25, 2, 96};
  41. char    o_list[1] =        {FALSE};
  42. char    o_number[1] =        {FALSE};
  43. char    o_readonly[1] =        {FALSE};
  44. char    o_remap[1] =        {TRUE};
  45. char    o_report[3] =        {5, 1, 127};
  46. char    o_scroll[3] =        {12, 1, 127};
  47. char    o_shell[60] =        SHELL;
  48. char    o_shiftwidth[3] =    {8, 1, 255};
  49. char    o_sidescroll[3] =    {8, 1, 40};
  50. char    o_sync[1] =        {NEEDSYNC};
  51. char    o_tabstop[3] =        {8, 1, 40};
  52. char    o_term[30] =        "?";
  53. char    o_flash[1] =        {TRUE};
  54. char    o_warn[1] =        {TRUE};
  55. char    o_wrapscan[1] =        {TRUE};
  56.  
  57. #ifndef CRUNCH
  58. char    o_beautify[1] =        {FALSE};
  59. char    o_exrc[1] =        {FALSE};
  60. char    o_mesg[1] =        {TRUE};
  61. char    o_more[1] =        {TRUE};
  62. char    o_novice[1] =        {FALSE};
  63. char    o_prompt[1] =        {TRUE};
  64. char    o_taglength[3] =    {0, 0, 30};
  65. char    o_terse[1] =        {FALSE};
  66. char    o_window[3] =        {0, 1, 24};
  67. char    o_wrapmargin[3] =    {0, 0, 255};
  68. char    o_writeany[1] =        {FALSE};
  69. #endif
  70.  
  71. #ifndef NO_ERRLIST
  72. char    o_cc[30] =        {CC_COMMAND};
  73. char    o_make[30] =        {MAKE_COMMAND};
  74. #endif
  75.  
  76. #ifndef NO_CHARATTR
  77. char    o_charattr[1] =        {FALSE};
  78. #endif
  79.  
  80. #ifndef NO_DIGRAPH
  81. char    o_digraph[1] =        {FALSE};
  82. char    o_flipcase[80]
  83. # ifdef CS_IBMPC
  84.     = {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245"}
  85. # endif
  86. # ifdef CS_LATIN1
  87.     /* initialized by initopts() */
  88. # endif
  89.     ;
  90. #endif
  91.  
  92. #ifndef NO_SENTENCE
  93. char    o_hideformat[1] =    {FALSE};
  94. #endif
  95.  
  96. #ifndef NO_EXTENSIONS
  97. char    o_inputmode[1] =    {FALSE};
  98. char    o_ruler[1] =        {FALSE};
  99. #endif
  100.  
  101. #ifndef NO_MAGIC
  102. char    o_magic[1] =        {TRUE};
  103. #endif
  104.  
  105. #ifndef NO_MODELINES
  106. char    o_modelines[1] =    {FALSE};
  107. #endif
  108.  
  109. #ifndef NO_SENTENCE
  110. char    o_paragraphs[30] =    "PPppIPLPQP";
  111. char    o_sections[30] =    "NHSHSSSEse";
  112. #endif
  113.  
  114. #if MSDOS
  115. char    o_pcbios[1] =        {TRUE};
  116. #endif
  117.  
  118. #ifndef NO_SHOWMATCH
  119. char    o_showmatch[1] =    {FALSE};
  120. #endif
  121.  
  122. #ifndef    NO_SHOWMODE
  123. char    o_smd[1] =        {FALSE};
  124. #endif
  125.  
  126.  
  127. /* The following describes the names & types of all options */
  128. #define BOOL    0
  129. #define    NUM    1
  130. #define    STR    2
  131. #define SET    0x01    /* this option has had its value altered */
  132. #define CANSET    0x02    /* this option can be set at any time */
  133. #define RCSET    0x06    /* this option can be set in a .exrc file only */
  134. #define NOSAVE    0x0a    /* this option should never be saved by mkexrc */
  135. #define WSET    0x20    /* is this the "window" size option? */
  136. #define MR    0x40    /* does this option affect the way text is displayed? */
  137. struct
  138. {
  139.     char    *name;    /* name of an option */
  140.     char    *nm;    /* short name of an option */
  141.     char    type;    /* type of an option */
  142.     char    flags;    /* boolean: has this option been set? */
  143.     char    *value;    /* value */
  144. }
  145.     opts[] =
  146. {
  147.     /* name            type    flags        value */
  148.     { "autoindent",    "ai",    BOOL,    CANSET,        o_autoindent    },
  149.     { "autoprint",    "ap",    BOOL,    CANSET,        o_autoprint    },
  150.     { "autotab",    "at",    BOOL,    CANSET,        o_autotab    },
  151.     { "autowrite",    "aw",    BOOL,    CANSET,        o_autowrite    },
  152. #ifndef CRUNCH
  153.     { "beautify",    "bf",    BOOL,    CANSET,        o_beautify    },
  154. #endif
  155. #ifndef NO_ERRLIST
  156.     { "cc",        "cc",    STR,    CANSET,        o_cc        },
  157. #endif
  158. #ifndef NO_CHARATTR
  159.     { "charattr",    "ca",    BOOL,    CANSET|MR,    o_charattr    },
  160. #endif
  161.     { "columns",    "co",    NUM,    SET|NOSAVE|MR,    o_columns    },
  162. #ifndef NO_DIGRAPH
  163.     { "digraph",    "dig",    BOOL,    CANSET,        o_digraph    },
  164. #endif
  165.     { "directory",    "dir",    STR,    RCSET,        o_directory    },
  166.     { "edcompatible","ed",    BOOL,    CANSET,        o_edcompatible    },
  167.     { "equalprg",    "ep",    STR,    CANSET,        o_equalprg    },
  168.     { "errorbells",    "eb",    BOOL,    CANSET,        o_errorbells    },
  169. #ifndef CRUNCH
  170.     { "exrc",    "exrc",    BOOL,    CANSET,        o_exrc        },
  171. #endif
  172.     { "exrefresh",    "er",    BOOL,    CANSET,        o_exrefresh    },
  173.     { "flash",    "vbell",BOOL,    CANSET,        o_flash        },
  174. #ifndef NO_DIGRAPH
  175.     { "flipcase",    "fc",    STR,    CANSET,        o_flipcase    },
  176. #endif
  177. #ifndef NO_SENTENCE
  178.     { "hideformat",    "hf",    BOOL,    CANSET|MR,    o_hideformat    },
  179. #endif
  180.     { "ignorecase",    "ic",    BOOL,    CANSET,        o_ignorecase    },
  181. #ifndef NO_EXTENSIONS
  182.     { "inputmode",    "im",    BOOL,    CANSET,        o_inputmode    },
  183. #endif
  184.     { "keytime",    "kt",    NUM,    CANSET,        o_keytime    },
  185.     { "keywordprg",    "kp",    STR,    CANSET,        o_keywordprg    },
  186.     { "lines",    "ls",    NUM,    SET|NOSAVE|MR,    o_lines        },
  187.     { "list",    "li",    BOOL,    CANSET|MR,    o_list        },
  188. #ifndef NO_MAGIC
  189.     { "magic",    "ma",    BOOL,    CANSET,        o_magic        },
  190. #endif
  191. #ifndef NO_ERRLIST
  192.     { "make",    "mk",    STR,    CANSET,        o_make        },
  193. #endif
  194. #ifndef CRUNCH
  195.     { "mesg",    "me",    BOOL,    CANSET,        o_mesg        },
  196. #endif
  197. #ifndef NO_MODELINES
  198.     { "modelines",    "ml",    BOOL,    CANSET,        o_modelines    },
  199. #endif
  200. #ifndef CRUNCH
  201.     { "more",    "mo",    BOOL,    CANSET,        o_more        },
  202.     { "novice",    "nov",    BOOL,    CANSET,        o_novice    },
  203. #endif
  204.     { "number",    "nu",    BOOL,    CANSET|MR,    o_number    },
  205. #ifndef NO_SENTENCE
  206.     { "paragraphs",    "para",    STR,    CANSET,        o_paragraphs    },
  207. #endif
  208. #if MSDOS
  209.     { "pcbios",    "pc",    BOOL,    SET|NOSAVE,    o_pcbios    },
  210. #endif
  211. #ifndef CRUNCH
  212.     { "prompt",    "pr",    BOOL,    CANSET,        o_prompt    },
  213. #endif
  214.     { "readonly",    "ro",    BOOL,    CANSET,        o_readonly    },
  215.     { "remap",    "remap",BOOL,    CANSET,        o_remap        },
  216.     { "report",    "re",    NUM,    CANSET,        o_report    },
  217. #ifndef NO_EXTENSIONS
  218.     { "ruler",    "ru",    BOOL,    CANSET,        o_ruler        },
  219. #endif
  220.     { "scroll",    "sc",    NUM,    CANSET,        o_scroll    },
  221. #ifndef NO_SENTENCE
  222.     { "sections",    "sect",    STR,    CANSET,        o_sections    },
  223. #endif
  224.     { "shell",    "sh",    STR,    CANSET,        o_shell        },
  225. #ifndef NO_SHOWMATCH
  226.     { "showmatch",    "sm",    BOOL,    CANSET,        o_showmatch    },
  227. #endif
  228. #ifndef    NO_SHOWMODE
  229.     { "showmode",    "smd",    BOOL,    CANSET,        o_smd        },
  230. #endif
  231.     { "shiftwidth",    "sw",    NUM,    CANSET,        o_shiftwidth    },
  232.     { "sidescroll",    "ss",    NUM,    CANSET,        o_sidescroll    },
  233.     { "sync",    "sy",    BOOL,    CANSET,        o_sync        },
  234.     { "tabstop",    "ts",    NUM,    CANSET|MR,    o_tabstop    },
  235. #ifndef CRUNCH
  236.     { "taglength",    "tl",    NUM,    CANSET,        o_taglength    },
  237. #endif
  238.     { "term",    "te",    STR,    SET,        o_term        },
  239. #ifndef CRUNCH
  240.     { "terse",    "tr",    BOOL,    CANSET,        o_terse        },
  241.     { "timeout",    "to",    BOOL,    CANSET,        o_keytime    },
  242. #endif
  243. #ifndef CRUNCH
  244.     { "window",    "wi",    NUM,    CANSET|MR|WSET,    o_window    },
  245.     { "wrapmargin",    "wm",    NUM,    CANSET,        o_wrapmargin    },
  246. #endif
  247.     { "wrapscan",    "ws",    BOOL,    CANSET,        o_wrapscan    },
  248. #ifndef CRUNCH
  249.     { "writeany",    "wr",    BOOL,    CANSET,        o_writeany    },
  250. #endif
  251.     { NULL, NULL, 0, CANSET, NULL }
  252. };
  253.  
  254.  
  255. /* This function initializes certain options from environment variables, etc. */
  256. void initopts()
  257. {
  258.     char    *val;
  259.     int    i;
  260.  
  261.     /* set some stuff from environment variables */
  262. #if MSDOS
  263.     if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
  264. #else
  265.     if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
  266. #endif
  267.     {
  268.         strcpy(o_shell, val);
  269.     }
  270.  
  271.     strcpy(o_term, termtype);
  272. #if MSDOS
  273.     if (strcmp(termtype, "pcbios"))
  274.     {
  275.         o_pcbios[0] = FALSE;
  276.     }
  277.     else
  278.     {
  279.         o_pcbios[0] = TRUE;
  280.     }
  281. #endif
  282.  
  283. #if AMIGA || MSDOS || TOS
  284.     if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
  285.     ||  (val = getenv("TEMP")))
  286.         strcpy(o_directory, val);
  287. #endif
  288.  
  289. #ifndef CRUNCH
  290.     if ((val = getenv("LINES")) && atoi(val) > 4) /* yes, ASSIGNMENT! */
  291.     {
  292.         LINES = atoi(val);
  293.     }
  294.     if ((val = getenv("COLUMNS")) && atoi(val) > 30) /* yes, ASSIGNMENT! */
  295.     {
  296.         COLS = atoi(val);
  297.     }
  298. #endif
  299.     *o_lines = LINES;
  300.     *o_columns = COLS;
  301.     *o_scroll = LINES / 2 - 1;
  302. #ifndef CRUNCH
  303.     if (o_window[0] == 0)
  304.     {
  305.         o_window[0] = o_window[2] = *o_lines;
  306.     }
  307. #endif
  308.  
  309.     /* disable the flash option if we don't know how to do a flash */
  310.     if (!has_VB)
  311.     {
  312.         for (i = 0; opts[i].value != o_flash; i++)
  313.         {
  314.         }
  315.         opts[i].flags &= ~CANSET;
  316.         *o_flash = FALSE;
  317.     }
  318.  
  319. #ifndef NO_DIGRAPH
  320. # ifdef CS_LATIN1
  321.     for (i = 0, val = o_flipcase; i < 32; i++)
  322.     {
  323.         /* leave out the multiply/divide symbols */
  324.         if (i == 23)
  325.             continue;
  326.  
  327.         /* add lower/uppercase pair */
  328.         *val++ = i + 0xe0;
  329.         *val++ = i + 0xc0;
  330.     }
  331.     *val = '\0';
  332. # endif /* CS_LATIN1 */
  333.  
  334.     /* initialize the ctype package */
  335.     _ct_init(o_flipcase);
  336. #else
  337.     _ct_init("");
  338. #endif /* not NO_DIGRAPH */
  339. }
  340.  
  341. /* This function lists the current values of all options */
  342. void dumpopts(all)
  343.     int    all;    /* boolean: dump all options, or just set ones? */
  344. {
  345. #ifndef NO_OPTCOLS
  346.     int    i, j, k;
  347.     char    nbuf[4];    /* used for converting numbers to ASCII */
  348.     int    widths[5];    /* width of each column, including gap */
  349.     int    ncols;        /* number of columns */
  350.     int    nrows;        /* number of options per column */
  351.     int    nset;        /* number of options to be output */
  352.     int    width;        /* width of a particular option */
  353.     int    todump[60];    /* indicies of options to be dumped */
  354.  
  355.     /* step 1: count the number of set options */
  356.     for (nset = i = 0; opts[i].name; i++)
  357.     {
  358.         if (all || (opts[i].flags & SET))
  359.         {
  360.             todump[nset++] = i;
  361.         }
  362.     }
  363.  
  364.     /* step two: try to use as many columns as possible */
  365.     for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
  366.     {
  367.         /* how many would go in this column? */
  368.         nrows = (nset + ncols - 1) / ncols;
  369.  
  370.         /* figure out the width of each column */
  371.         for (i = 0; i < ncols; i++)
  372.         {
  373.             widths[i] = 0;
  374.             for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
  375.             {
  376.                 /* figure out the width of a particular option */
  377.                 switch (opts[todump[k]].type)
  378.                 {
  379.                   case BOOL:
  380.                     if (!*opts[todump[k]].value)
  381.                         width = 2;
  382.                     else
  383.                         width = 0;
  384.                     break;
  385.  
  386.                   case STR:
  387.                     width = 3 + strlen(opts[todump[k]].value);
  388.                     if (width > MAXWIDTH)
  389.                         width = MAXWIDTH;
  390.                     break;
  391.  
  392.                   case NUM:
  393.                     width = 4;
  394.                     break;
  395.                 }
  396.                 width += strlen(opts[todump[k]].name);
  397.  
  398.                 /* if this is the widest so far, widen col */
  399.                 if (width > widths[i])
  400.                 {
  401.                     widths[i] = width;
  402.                 }
  403.             }
  404.  
  405.         }
  406.  
  407.         /* if the total width is narrow enough, then use it */
  408.         for (width = -2, i = 0; i < ncols; i++)
  409.         {
  410.             width += widths[i] + 2;
  411.         }
  412.         if (width < COLS - 1)
  413.         {
  414.             break;
  415.         }
  416.     }
  417.  
  418.     /* step 3: output the columns */
  419.     nrows = (nset + ncols - 1) / ncols;
  420.     for (i = 0; i < nrows; i++)
  421.     {
  422.         for (j = 0; j < ncols; j++)
  423.         {
  424.             /* if we hit the end of the options, quit */
  425.             k = i + j * nrows;
  426.             if (k >= nset)
  427.             {
  428.                 break;
  429.             }
  430.  
  431.             /* output this option's value */
  432.             width = 0;
  433.             switch (opts[todump[k]].type)
  434.             {
  435.               case BOOL:
  436.                 if (!*opts[todump[k]].value)
  437.                 {
  438.                     qaddch('n');
  439.                     qaddch('o');
  440.                     width = 2;
  441.                 }
  442.                 qaddstr(opts[todump[k]].name);
  443.                 width += strlen(opts[todump[k]].name);
  444.                 break;
  445.  
  446.               case NUM:
  447.                 sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
  448.                 qaddstr(opts[todump[k]].name);
  449.                 qaddch('=');
  450.                 qaddstr(nbuf);
  451.                 width = 4 + strlen(opts[todump[k]].name);
  452.                 break;
  453.  
  454.               case STR:
  455.                 qaddstr(opts[todump[k]].name);
  456.                 qaddch('=');
  457.                 qaddch('"');
  458.                 strcpy(tmpblk.c, opts[todump[k]].value);
  459.                 width = 3 + strlen(tmpblk.c);
  460.                 if (width > MAXWIDTH)
  461.                 {
  462.                     width = MAXWIDTH;
  463.                     strcpy(tmpblk.c + MAXWIDTH - 6, "...");
  464.                 }
  465.                 qaddstr(tmpblk.c);
  466.                 qaddch('"');
  467.                 width += strlen(opts[todump[k]].name);
  468.                 break;
  469.             }
  470.  
  471.             /* pad the field to the correct size */
  472.             if (k + nrows <= nset)
  473.             {
  474.                 while (width < widths[j] + 2)
  475.                 {
  476.                     qaddch(' ');
  477.                     width++;
  478.                 }
  479.             }
  480.         }
  481.         addch('\n');
  482.         exrefresh();
  483.     }
  484. #else
  485.     int    i;
  486.     int    col;
  487.     char    nbuf[4];
  488.  
  489.     for (i = col = 0; opts[i].name; i++)
  490.     {
  491.         /* if not set and not all, ignore this option */
  492.         if (!all && !(opts[i].flags & SET))
  493.         {
  494.             continue;
  495.         }
  496.  
  497.         /* align this option in one of the columns */
  498.         if (col > 52)
  499.         {
  500.             addch('\n');
  501.             col = 0;
  502.         }
  503.         else if (col > 26)
  504.         {
  505.             while (col < 52)
  506.             {
  507.                 qaddch(' ');
  508.                 col++;
  509.             }
  510.         }
  511.         else if (col > 0)
  512.         {
  513.             while (col < 26)
  514.             {
  515.                 qaddch(' ');
  516.                 col++;
  517.             }
  518.         }
  519.  
  520.         switch (opts[i].type)
  521.         {
  522.           case BOOL:
  523.             if (!*opts[i].value)
  524.             {
  525.                 qaddch('n');
  526.                 qaddch('o');
  527.                 col += 2;
  528.             }
  529.             qaddstr(opts[i].name);
  530.             col += strlen(opts[i].name);
  531.             break;
  532.  
  533.           case NUM:
  534.             sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
  535.             qaddstr(opts[i].name);
  536.             qaddch('=');
  537.             qaddstr(nbuf);
  538.             col += 4 + strlen(opts[i].name);
  539.             break;
  540.  
  541.           case STR:
  542.             qaddstr(opts[i].name);
  543.             qaddch('=');
  544.             qaddch('"');
  545.             qaddstr(opts[i].value);
  546.             qaddch('"');
  547.             col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
  548.             break;
  549.         }
  550.         exrefresh();
  551.     }
  552.     if (col > 0)
  553.     {
  554.         addch('\n');
  555.         exrefresh();
  556.     }
  557. #endif
  558. }
  559.  
  560. #ifndef NO_MKEXRC
  561. /* This function saves the current configuration of options to a file */
  562. void saveopts(fd)
  563.     int    fd;    /* file descriptor to write to */
  564. {
  565.     int    i;
  566.     char    buf[256], *pos;
  567.  
  568.     /* write each set options */
  569.     for (i = 0; opts[i].name; i++)
  570.     {
  571.         /* if unset or unsettable, ignore this option */
  572.         if ((opts[i].flags & (SET|CANSET|NOSAVE)) != (SET|CANSET))
  573.         {
  574.             continue;
  575.         }
  576.  
  577.         strcpy(buf, "set ");
  578.         pos = &buf[4];
  579.         switch (opts[i].type)
  580.         {
  581.           case BOOL:
  582.             if (!*opts[i].value)
  583.             {
  584.                 *pos++='n';
  585.                 *pos++='o';
  586.             }
  587.             strcpy(pos, opts[i].name);
  588.             strcat(pos, "\n");
  589.             break;
  590.  
  591.           case NUM:
  592.             sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
  593.             break;
  594.  
  595.           case STR:
  596.             sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
  597.             break;
  598.         }
  599.         twrite(fd, buf, (unsigned)strlen(buf));
  600.     }
  601. }
  602. #endif
  603.  
  604.  
  605. /* This function changes the values of one or more options. */
  606. void setopts(assignments)
  607.     char    *assignments;    /* a string containing option assignments */
  608. {
  609.     char    *name;        /* name of variable in assignments */
  610.     char    *value;        /* value of the variable */
  611.     char    *scan;        /* used for moving through strings */
  612.     char    *build;        /* used for copying chars from "scan" */
  613.     char    *prefix;    /* pointer to "neg" or "no" at front of a boolean */
  614.     int    quote;        /* boolean: inside '"' quotes? */
  615.     int    i, j;
  616.  
  617. #ifndef CRUNCH
  618.     /* reset the upper limit of "window" option to lines-1 */
  619.     *o_window = *o_lines - 1;
  620. #endif
  621.  
  622.     /* for each assignment... */
  623.     for (name = assignments; *name; )
  624.     {
  625.         /* skip whitespace */
  626.         if (*name == ' ' || *name == '\t')
  627.         {
  628.             name++;
  629.             continue;
  630.         }
  631.  
  632.         /* after the name, find the value (if any) */
  633.         for (scan = name; isalnum(*scan); scan++)
  634.         {
  635.         }
  636.         if (*scan == '=')
  637.         {
  638.             *scan++ = '\0';
  639.             value = build = scan;
  640.             for (quote = FALSE; *scan && (quote || !isspace(*scan)); scan++)
  641.             {
  642.                 if (*scan == '"')
  643.                 {
  644.                     quote = !quote;
  645.                 }
  646.                 else if (*scan == '\\' && scan[1])
  647.                 {
  648.                     *build++ = *++scan;
  649.                 }
  650.                 else
  651.                 {
  652.                     *build++ = *scan;
  653.                 }
  654.             }
  655.             if (*scan)
  656.                 scan++;
  657.             *build = '\0';
  658.         }
  659.         else /* no "=" so it is probably boolean... */
  660.         {
  661.             if (*scan)
  662.             {
  663.                 *scan++ = '\0';
  664.             }
  665.             value = NULL;
  666.             prefix = name;
  667. #ifndef CRUNCH
  668.             if (!strcmp(name, "novice"))
  669.                 /* don't check for a "no" prefix */;
  670.             else
  671. #endif
  672.             if (prefix[0] == 'n' && prefix[1] == 'o')
  673.                 name += 2;
  674.             else if (prefix[0] == 'n' && prefix[1] == 'e' && prefix[2] == 'g')
  675.                 name += 3;
  676.         }
  677.  
  678.         /* find the variable */
  679.         for (i = 0;
  680.              opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
  681.              i++)
  682.         {
  683.         }
  684.  
  685.         /* change the variable */
  686.         if (!opts[i].name)
  687.         {
  688.             msg("invalid option name \"%s\"", name);
  689.         }
  690.         else if ((opts[i].flags & CANSET) != CANSET)
  691.         {
  692.             msg("option \"%s\" can't be altered", name);
  693.         }
  694.         else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
  695.         {
  696.             msg("option \"%s\" can only be set in a %s file", name, EXRC);
  697.         }
  698.         else if (value)
  699.         {
  700.             switch (opts[i].type)
  701.             {
  702.               case BOOL:
  703.                 msg("option \"[no]%s\" is boolean", name);
  704.                 break;
  705.  
  706.               case NUM:
  707.                 j = atoi(value);
  708.                 if (j == 0 && *value != '0')
  709.                 {
  710.                     msg("option \"%s\" must have a numeric value", name);
  711.                 }
  712.                 else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
  713.                 {
  714.                     msg("option \"%s\" must have a value between %d and %d",
  715.                         name, opts[i].value[1], opts[i].value[2] & 0xff);
  716.                 }
  717.                 else
  718.                 {
  719.                     *opts[i].value = atoi(value);
  720.                     opts[i].flags |= SET;
  721.                 }
  722.                 break;
  723.  
  724.               case STR:
  725.                 strcpy(opts[i].value, value);
  726.                 opts[i].flags |= SET;
  727.                 break;
  728.             }
  729.             if (opts[i].flags & MR)
  730.             {
  731.                 redraw(MARK_UNSET, FALSE);
  732.             }
  733. #ifndef CRUNCH
  734.             if (opts[i].flags & WSET)
  735.             {
  736.                 wset = TRUE;
  737.             }
  738. #endif
  739.         }
  740.         else /* valid option, no value */
  741.         {
  742.             if (opts[i].type == BOOL)
  743.             {
  744.                 if (prefix == name)
  745.                     *opts[i].value = TRUE;
  746.                 else if (prefix[1] == 'o')
  747.                     *opts[i].value = FALSE;
  748.                 else
  749.                     *opts[i].value = !*opts[i].value;
  750.  
  751.                 opts[i].flags |= SET;
  752.                 if (opts[i].flags & MR)
  753.                 {
  754.                     redraw(MARK_UNSET, FALSE);
  755.                 }
  756.             }
  757.             else
  758.             {
  759.                 msg("option \"%s\" must be given a value", name);
  760.             }
  761.         }
  762.  
  763.         /* move on to the next option */
  764.         name = scan;
  765.     }
  766.  
  767.     /* special processing ... */
  768.  
  769. #ifndef CRUNCH
  770.     /* if "novice" is set, then ":set report=1 showmode nomagic" */
  771.     if (*o_novice)
  772.     {
  773.         *o_report = 1;
  774. # ifndef NO_SHOWMODE
  775.         *o_smd = TRUE;
  776. # endif
  777. # ifndef NO_MAGIC
  778.         *o_magic = FALSE;
  779. # endif
  780.     }
  781. #endif
  782.  
  783.     /* if "readonly" then set the READONLY flag for this file */
  784.     if (*o_readonly)
  785.     {
  786.         setflag(file, READONLY);
  787.     }
  788.  
  789. #ifndef NO_DIGRAPH
  790.     /* re-initialize the ctype package */
  791.     _ct_init(o_flipcase);
  792. #endif /* not NO_DIGRAPH */
  793.  
  794.     /* copy o_lines and o_columns into LINES and COLS */
  795.     LINES = (*o_lines & 255);
  796.     COLS = (*o_columns & 255);
  797. }
  798.